找传奇、传世资源到传世资源站!

C#的服务器程序

8.5玩家评分(1人评分)
下载后可评
介绍 评论 失效链接反馈

from clipboard
using System;                            //包含基本类和基类
using System.Collections.Generic;        //用于定义泛型集合的接口和类
using System.ComponentModel;             //实现组件设计和运行时行为的类
using System.Data;                       //提供了对数据库的访问支持
using System.Drawing;                    //提供了对图形绘制的支持
using System.Text;                       //包含用于字符编码等功能的对象
using System.Windows.Forms;              //支持Windows窗体的类
using System.Net;                       //为当前网络上使用的多种协议提供了简单的编程接口
using System.Net.Sockets;               //为网络编程开发人员提供了Windows Sockets (Winsock)接口的托管实现
using System.Threading;                 //提供了一些可以进行多线程编程的类和接口
using System.Collections;               //包含可用的集合类和相关的接口,提供了集合的基本功能

namespace AgentServer                   //程序的命名空间,也是项目名称AgentServer
{
    public partial class ServerForm : Form   //窗口类
    {
        struct ClientInfo          //结构体ClientInfo   struct语句为程序定义了一个带有多个成员的新的数据类型,struct不能指定为protected
        {
            public EndPoint endpoint;    //公有的终结点  endpoint  //网络地址和端口号的组合称为终结点;EndPoint类表示这个终结点,它提供表示网络资源或服务的抽象,用以标志网络地址等信息
            public string strName;       //公有的字符串变量 strName
        }
        ArrayList clientList;           //ArrayList在System.Collections中,定义了ArrayList类型数组clientList
        string ServerIp;                //字符串变量 ServerIP
        string ServerPort;              //字符串变量ServerPort
        
        Socket serverSocket;                 //定义Socket变量serverSocket
        byte[] byteData = new byte[1024];    //定义一个byte类型一维数组byteData,它有1024个元素   byte无符号整数 0-255

        public ServerForm()                 //窗体类ServerForm的构造函数
        {
            CheckForIllegalCrossThreadCalls = false;    //在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件,如果需要访问窗口中的控件,可以在窗口构造函数中将CheckForIllegalCrossThreadCalls设置为false
            clientList = new ArrayList();   //新建数组clientList
            InitializeComponent();          //完成初始化操作
            ServerIp = System.Configuration.ConfigurationSettings.AppSettings["ServerIp"];      //读取配置文件信息,ConfigurationSettings类在命名空间System.Configuration中,AppSettings是ConfigurationSettings的属性,ServerIp = 127.0.0.1
            ServerPort = System.Configuration.ConfigurationSettings.AppSettings["ServerPort"];  //读取配置文件ServerPort = 1110    #Client status info
            try     //抛出异常
            {
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);  //创建一个Socket实例,基于UDP的网络协议 //Socket类的构造函数使用三个参数来定义创建的Socket实例,AddressFamily用来指定网络类型,SocketType用来指定套接字类型,ProtocolType用来指定网络协议,三个参数都是在命名空间System.Net.Sockets中定义的枚举类型,它们不能任意组合;若是基于TCP应该serverSocket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ServerIp), int.Parse(ServerPort));   //用ServerIp和ServerPort初始化IPEndPoint类的实例ipEndPoint ;IPAddress.Parse(ServerIP)将ServerIp字符串转换为IPAddress实例;int.Parse(ServerPort)将数字类型字符串ServerPort转换为int型 //IPEndPoint类包含应用程序连接到主机上的服务所需的主机和端口号信息,通过组合服务的主机IP地址和端口号,IPEndPoint类形成到服务的连接点
                serverSocket.Bind(ipEndPoint);      //服务器端套接字serverSocket与终结点ipEndPoint相关联

                IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);    //初始化IPEndPoint类的实例 ipeSender;IPAddress.Any表示本地系统可用的任何IP地址,指示服务器应侦听所有网络接口上的客户端活动;端口号0是为了避免写死端口号的做法,也是为了从本地系统中找到可用端口,故用0表示连接参数
                EndPoint epSender = (EndPoint)ipeSender;                    //强制类型转换,将IPEndPoint类型的ipeSender转换为EndPoint类型的epSender

               // byteData = new byte[1024];                                //Socket.BeginReveiveFrom(buffer, offset, size, socketFlags,remoteEP,callback,state )   buffer接收数据的存储位置,offset从零开始的位置,buffer在其中存储数据的参数,size要接收的字节数,socketFlags是SocketFlags值的按位组合,remoteEP是EndPoint表示的数据源,callback是AsyncCallback委托,state包含此请求状态信息的对象
                serverSocket.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);    //以异步的方式从指定的网络设备上接收数据;数组byteData是接收到的数据的存储位置,0表示接收数据存储在byteData从0开始的位置,byteData.Length表示接收数据的大小,SocketFlags.None表示对这次调用不使用标志,SocketFlags枚举类型参数指定套接字的发送和接收行为,ref epSender终结点,ref表示引用传递,AsyncCallback委托,在异步调用完成时要调用的方法,

                if (lbUsers.Items.Count <= 0)      //lbUser.Items.Count表示列表框lbUser中列表项的个数  //lbUsers是ListBox控件,ListBox控件的作用是显示长的文件列表
                {
                    btnSendMessage.Enabled = false;  //Button btnSendMessage的Enabled属性设置为false,也就是使控件不可用,禁止该控件与用户或程序交互
                    btnBrocast.Enabled = false;      //Button btnBrocast的Enabled属性设置为false      
                }
            }
            catch (Exception ex)    //捕获异常
            {
                MessageBox.Show(ex.Message, "ServerForm:UdpTcpServer", MessageBoxButtons.OK, MessageBoxIcon.Error);  //使用消息对话框给用户提示,对话框中有OK按钮和Error按钮
            }
        }

        private void btnSendMessage_Click(object sender, EventArgs e)       //btnSendMessage按钮的单击事件
        {
            if (lbUsers.SelectedItems.Count > 0)                            //lbUsers.Selected.Count是用户选择的项目数
            {
                if (txtMessage.Text.Length > 0)                             //文本框textMessage中字符个数大于0
                {
                    string sendMessage = txtMessage.Text;     //发送的消息是“talk|Server|txtMessage内容|”
                    byte[] byteDataSend = new byte[1024];                   //定义一个byte类型数组byteDataSend,它有1024个元素
                    byteDataSend = Encoding.ASCII.GetBytes(sendMessage);   //将sendMessage这个字符串根据ASCII编码采用byte表示并赋值给byteDataSend;

                    foreach (string user in lbUsers.SelectedItems)         //在lbUsers列表框选中user
                    {
                        foreach (ClientInfo client in clientList)          //迭代clientList中的client
                        {
                            if (client.strName.ToString().Trim() == user.Trim())    //将client的strName属性转换为字符串类型,并去掉前后空格
                            {
                                serverSocket.BeginSendTo(byteDataSend, 0, byteDataSend.Length, SocketFlags.None, client.endpoint, new AsyncCallback(OnSend), client.endpoint);      //以异步的方式将数据发送到特定的远程主机 Sockets.BeginSendTo方法(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback,Object)
                            }   //byteDataSend要发送的数据,0表示byteDataSend从位置0开始发送数据,byteDataSend.Length表示要发送的字节数,SocketFlags.None表示这次调用不使用标志,client.endpoint表示客户端,也就是包含此请求信息的对象
                        }
                    }
                    txt_output.AppendText("服务器:" txtMessage.Text Environment.NewLine);       //RichTextBox除了具有TextBox的所有功能外,还能提供富文本显示的功能  //在富文本框rtbHistoryMessage的文本末尾追加“服务器:txtMessage的内容换行”Environment.NewLine属性是获取为此环境定义的换行符
                    txtMessage.Text = null;     //文本框txtMessage属性置为空
                }
                else
                {
                    MessageBox.Show("不能发送空信息!");    //向用户显示消息“不能发送空信息!”
                }
            }
            else
            {
                MessageBox.Show("请选择用户,再发送!");    //向用户显示“请选择用户,再发送!”
            }
        }

        public void OnSend(IAsyncResult ar)     //IAsyncResult接口表示异步操作的状态  ar存储异步操作的状态信息
        {
            try     //抛出异常
            {
                serverSocket.EndSend(ar);   //serverSocket.EndSend(ar)结束挂起的异步发送
            }
            catch (Exception ex)    //捕获异常
            {
                MessageBox.Show(ex.Message, "OnSend:UdpTcpServer", MessageBoxButtons.OK, MessageBoxIcon.Error);     //使用消息对话框给用户提示,对话框中有OK按钮和Error按钮
            }
        }
        
        private void OnReceive(IAsyncResult ar)         //IAsyncResult接口表示异步操作的状态  ar存储异步操作的状态信息
        {
            try     //抛出异常
            {
              
                IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0); //初始化IPEndPoint类的实例 ipeSender;IPAddress.Any表示本地系统可用的任何IP地址,指示服务器应侦听所有网络接口上的客户端活动;端口号0是为了避免写死端口号的做法,也是为了从本地系统中找到可用端口,故用0表示连接参数
                EndPoint epSender = (EndPoint)ipeSender;                 //强制类型转换,将IPEndPoint类型的ipeSender转换为EndPoint类型的epSender

                serverSocket.EndReceiveFrom(ar, ref epSender);          //结束挂起的异步读取从特定的终结点 serverSocket.EndReceiveFrom(IAsyncResult, EndPoint) IAsyncResult用于存储状态信息和对此异步操作的任何用户定义数据,EndPoint源EndPoint

                string msgReceived = Encoding.ASCII.GetString(byteData).TrimEnd('\0').Trim();  //将byteData这个字符串根据ASCII编码采用string表示,并赋值给msgReceived
                string[] tokens = msgReceived.Split(new char[] { '|' });  //将字符串msgReceived使用"|"进行拆分,并将拆分后结果赋给字符串类型数组tokens
                if (tokens.Length > 4)
                    return;
                if (tokens[0] == "login")    //若数组tokens的第零个元素是"login" Begin|Login|ClientName|End
                {
                    ClientInfo clientInfo = new ClientInfo();       //声明clientInfo,类型为ClientInfo
                    clientInfo.endpoint = epSender;                 //clientInfo详述,endpoint属性为epSender
                    clientInfo.strName = tokens[1].TrimEnd('\0');                 //strName为tokens第一个元素

                    int nIndex = 0;                                //索引值nIndex初始化为0
                    foreach (ClientInfo client in clientList)      //迭代clientList中的client
                    {
                        string client_name = client.strName.ToString().Trim();  //client的strName属性转换为字符串并去掉前后空格,然后赋值给client_name
                        string strEndPoint = client.endpoint.ToString();        //client的endpoint属性转换为字符串然后赋值给strEndPoint
                        string strepSender = epSender.ToString();              //epSpender转换为字符串然后赋值给strepSender
                        if (client_name == tokens[1])                          //client_name为tokens数组第一个元素
                        {

                            clientList.RemoveAt(nIndex);                       //移除clientList索引nIndex处的元素
                            lbUsers.Items.RemoveAt(nIndex);                    //移除将列表框lbUsers索引项nIdex
                            break;
                        }
                        nIndex;
                    }

                    clientList.Add(clientInfo);         //将clientInfo添加到clientList末尾
                    lbUsers.Items.Add(tokens[1]);       //将tokens[1]添加到列表框lbUsers中

                    btnBrocast.Enabled = true;          //使按钮btnBroadcast可用,可与用户或程序交互
                    btnSendMessage.Enabled = true;      //使按钮btnSendMessage可用,可与用户或程序交互
                    string sendmessage = "online";      //定义字符串变量sendmessage为"online"
                    byteData = Encoding.ASCII.GetBytes(sendmessage);    //将字符串变量sendmessage根据ASCII编码表示成byte类型并赋值给byteData
                    serverSocket.BeginSendTo(byteData, 0, byteData.Length, SocketFlags.None, clientInfo.endpoint, new AsyncCallback(OnSend), clientInfo.endpoint);  //以异步的方式将数据发送到特定的远程主机
                    //byteData要发送的数据,0表示byteData从位置0开始发送数据,byteData.Length表示要发送的字节数,SocketFlags.None表示这次调用不使用标志,clientInfo.endpoint表示客户端,也就是包含此请求信息的对象
                    string output = tokens[1].TrimEnd('\0') "已登录!" "\r\n";
                   int tokenlength=tokens[1].Trim().Length;
                   txt_output.AppendText(output);    
                }
                else if (tokens[0] == "logout")         //若数组tokens的第零个元素是"logout"
                {
                    int nIndex = 0;                     //索引值nIndex初始化为0

                    foreach (ClientInfo client in clientList)                //迭代clientList中的client
                    {
                        string strEndPoint = client.endpoint.ToString();     //client的endpoint属性转换为字符串并赋值给strEndPoint
                        string strepSender = epSender.ToString();            //epSender转换为字符串并赋值给strepSender

                        if (strEndPoint.Equals(strepSender))                 //strEndPoint与strepSender引用相等
                        {
                            clientList.RemoveAt(nIndex);                     //移除clientList中索引nIndex元素
                            lbUsers.Items.RemoveAt(nIndex);                  //移除列表框lbUser索引项nIndex
                            break;
                        }           
                        nIndex;
                    }

                    string strMessage = tokens[1];                          //将数组tokens第一个元素赋值给strMessage
                    string output = tokens[1].TrimEnd('\0') "已退出!" "\r\n";
                    txt_output.AppendText(output);                 //将strMessage添加到富文本框rtbHistoryMessage中
                }
                else if (tokens[0] == "talk" && tokens.Length==4)                               //数组tokens第零个元素为"talk"
                {
                    string source = tokens[1];
                    string distinction = tokens[2];
                    string message = tokens[3];
                    txt_output.AppendText(msgReceived "\r\n");

                    string sendMessage = msgReceived;     //发送的消息是“talk|Server|txtMessage内容|”
                    byte[] byteDataSend = new byte[1024];                   //定义一个byte类型数组byteDataSend,它有1024个元素
                    byteDataSend = Encoding.ASCII.GetBytes(sendMessage.TrimEnd('\0'));   //将sendMessage这个字符串根据ASCII编码采用byte表示并赋值给byteDataSend;

                
                        foreach (ClientInfo client in clientList)          //迭代clientList中的client
                        {
                            if (client.strName.ToString().TrimEnd('\0').Trim() == distinction)    //将client的strName属性转换为字符串类型,并去掉前后空格
                            {
                                serverSocket.BeginSendTo(byteDataSend, 0, byteDataSend.Length, SocketFlags.None, client.endpoint, new AsyncCallback(OnSend), client.endpoint);      //以异步的方式将数据发送到特定的远程主机 Sockets.BeginSendTo方法(Byte[], Int32, Int32, SocketFlags, EndPoint, AsyncCallback,Object)
                            }    
                        }
                 

                }
                byteData = new byte[1024];      //定义一个byte类型数组byteData,它有1024个元素
                serverSocket.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
             
              
            }   //以异步的方式从指定的网络设备上接收数据;数组byteData是接收到的数据的存储位置,0表示接收数据存储在byteData从0开始的位置,byteData.Length表示接收数据的大小,SocketFlags.None表示对这次调用不使用标志,SocketFlags枚举类型参数指定套接字的发送和接收行为,ref epSender终结点,ref表示引用传递,AsyncCallback委托,在异步调用完成时要调用的方法,
            catch (Exception ex)    //抛出异常
            {
                MessageBox.Show(ex.Message, "OnReceive:UdpTcpServer", MessageBoxButtons.OK, MessageBoxIcon.Error);     //使用消息对话框给用户提示,对话框中有OK按钮和Error按钮
            }

        }

        private void ServerSendtoClient(string message, EndPoint clientednpoint)    //server端向clieent端发送消息
        {

            string sendmessage = "talk|Server|" message "\n";                 //字符串变量sendmessage赋值为“talk|Server|message内容|换行”
            byteData = Encoding.ASCII.GetBytes(sendmessage);                       //将sendmessage根据ASCII编码转换为byte类型并赋值给byteData
            serverSocket.BeginSendTo(byteData, 0, byteData.Length, SocketFlags.None, clientednpoint, new AsyncCallback(OnSend), clientednpoint);   //以异步方式将数据发送到远程主机
         }     //byteData要发送的数据,0表示byteData从位置0开始发送数据,byteData.Length表示要发送的字节数,SocketFlags.None表示这次调不使用标志,clientedpoint表示客户端,也就是包含此请求信息的对象

      /*  private void OnProcessMessage(string clientname, string message, EndPoint epSender)  //
        {

                    string[] command = message.Split(new char[] { ':' });     //将字符串message使用":"进行拆分,并将拆分后结果赋给字符串类型数组command
                 
                    foreach (ClientInfo client in clientList)             //迭代clientList中的client
                    {
                           string client_name=client.strName.ToString().Trim();       //将client的strName属性转换为字符串,然后去掉前后空格并赋值给client_name
                            if (client_name == command[1].Trim())                      //client_name为FireControlPanel火控控制面板
                            {
                             ServerSendtoClient(message, client.endpoint);                    //调用ServerSendtoClient函数
                            }
                        
                     }
        }*/

        private void btnBrocast_Click(object sender, EventArgs e)       //按钮btnBroad_Click的单击事件
        {
            string sendMessage = "talk|" "ServerBrcas|" txtMessage.Text "|\n";     //字符串变量sendMessage为 “talk|服务器txtMessage内容换行”
            byte[] byteDataBrocast = new byte[1024];        //定义一个byte类型数组byteDataBroadcast,它有1024个元素
            byteDataBrocast = Encoding.ASCII.GetBytes(sendMessage);     //将sendMessage根据ASCII编码转换为byte

            foreach (ClientInfo ci in clientList)  //迭代clientList
            {
                EndPoint epSender = ci.endpoint;  //将ci的endpoint属性赋值给epSender
                serverSocket.BeginSendTo(byteDataBrocast, 0, byteDataBrocast.Length, SocketFlags.None, epSender, new AsyncCallback(OnSend), epSender);
            }       //以异步方式将数据发送到远程主机

            txt_output.AppendText("服务器广播:" txtMessage.Text Environment.NewLine);   //富文本框显示“服务器:txtMessage内容换行”
            txtMessage.Text = null;     //txtMessage置为空
            sendMessage = null;         //sendMessage置为空
        }

        private void lbUsers_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void rtbHistoryMessage_TextChanged(object sender, EventArgs e)
        {

        }

    }
}

评论

发表评论必须先登陆, 您可以 登陆 或者 注册新账号 !


在线咨询: 问题反馈
客服QQ:174666394

有问题请留言,看到后及时答复